		//chatServer.c
		//Ashish Tomar
		//2009/1/27
		//Network Security -- HW0
		
		//xxxxxx
		//see list memeory allocation
		//see char * and line input
		//xxxxxx
		#include "md5wrapper.h"
		#include <stdio.h>
		#include <string.h>
		#include <sys/types.h>
		#include <sys/socket.h>
		#include <netdb.h>
		#include <arpa/inet.h>
		#include <stdlib.h>
		#include <unistd.h>
		#include <errno.h>
		#include <netinet/in.h>
		#include <sys/wait.h>
		#include <signal.h>
		#include <pthread.h>

		#define PORT "3492"  // the port users will be connecting to

		#define BACKLOG 10     // how many pending connections queue will hold
		#define MAXDATASIZE 1000 


		pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
		
		void *threaded_server( void *fdess);

		struct Clientss
		{
			char name[MAXDATASIZE];
			char pass[MAXDATASIZE];
			char passkey[MAXDATASIZE];
			int fdno;
			int test;
			int flag;
		};

	typedef struct Clientss Client;

	
		struct ClientDatabase
		{
			char *name;
			char *pass;
			char *key;
		struct ClientDatabase *next;
		} *head;
	typedef struct ClientDatabase item;


char * search(item *q,char *nam,char *passs)
{ 
	char *ret=" ";
	if(q==NULL)
{ 
	printf("\nNo Database\n");
}
else
	{
//printf("\n");
			while(q!=NULL)

			{ 
//			printf("%s:",q->arr);
				if(!(strcmp(q->name,nam)))
				{
if(!(strcmp(q->pass,passs)))
					{
return q->key;
					}
				}
			q=q->next;

			}
			//printf("\n");
	}

return ret;
}



item* append(item **q,char *var,char *passs,char *keyy)
{ 
						item *temp,*r, *ret;

					temp = *q;

					if(*q==NULL)

					{ temp = (item *)malloc(sizeof(item));

					temp->name=var;
					temp->pass=passs;
					temp->key=keyy;

					temp->next=NULL;

					*q=temp;
					//q=&temp;
					ret =*q;

					}

					else

					{ 
						temp = *q;
							ret= *q;
					while(temp->next !=NULL)

					{ temp=temp->next;

					}

					r = (item *)malloc(sizeof(item));

					r->name=var;
					r->pass=passs;
					r->key=keyy;

					r->next=NULL;

					temp->next=r;

					}

return ret;
}










void del (item *p,char *num)
 {
item *temp, *m, *temp2;
temp=p;
      while(temp!=NULL)
    {
      if(!(strcmp(temp->name, num)))
       {
           if(temp==p)
           {
              p=temp->next;
			  head=p;
			  temp2 =temp;
			  temp=temp->next;
              free(temp2);
              
           }
           else
         {
           m->next=temp->next;
		   temp2 =temp;
		    temp=temp->next;
           free(temp2);
           
         }
      }else
        {
           m=temp;
          temp= temp->next;
        }

}
    
}




	Client list[5];
	int num=0;
	int numlist=0;

	int curnum=0;


		void sigchld_handler(int s)
		{
			while(waitpid(-1, NULL, WNOHANG) > 0);
		}


		void *get_in_addr(struct sockaddr *sa)
		{
			if (sa->sa_family == AF_INET) {
				return &(((struct sockaddr_in*)sa)->sin_addr);
			}

			return &(((struct sockaddr_in6*)sa)->sin6_addr);
		}



		int main(int argc, char *argv[])
		{
							int sockfd, new_fd,numbytes;  // listen on sock_fd, new connection on new_fd
							struct addrinfo hints, *servinfo, *p;
							struct sockaddr_storage their_addr; // connector's address information
							socklen_t sin_size;
							struct sigaction sa;
							char buf[MAXDATASIZE];
							int yes=1;
							char s[INET6_ADDRSTRLEN];
							pthread_t thread1[10];

							int rv;

							memset(&hints, 0, sizeof hints);
							hints.ai_family = AF_UNSPEC;
							hints.ai_socktype = SOCK_STREAM;
							hints.ai_flags = AI_PASSIVE; // use my IP


							head=append(&head,"ashish","ash","no1");
							

							head=append(&head,"arpit","arp","no2");
							

							head=append(&head,"manasa","manu","no3");

							if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) == -1) 
							{
								printf( "getaddrinfo: \n");
								return 1;
							}
						for(p = servinfo; p != NULL; p = p->ai_next)
							{
								if ((sockfd = socket(p->ai_family, p->ai_socktype,p->ai_protocol)) == -1) 
								{
									perror("server: socket");
									continue;
								}

								if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,sizeof(int)) == -1) 
								{
									perror("setsockopt");
									exit(1);
								}

								if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1)
								{
									close(sockfd);
									perror("server: bind");
									continue;
								}

								break;
							}

							if (p == NULL) 
							{
								fprintf(stderr, "server: failed to bind\n");
								return 2;
							}

							freeaddrinfo(servinfo); // all done with this structure

							if (listen(sockfd, BACKLOG) == -1)
							{
								perror("listen");
								exit(1);
							}

							sa.sa_handler = sigchld_handler; // reap all dead processes
							sigemptyset(&sa.sa_mask);
							sa.sa_flags = SA_RESTART;
							if (sigaction(SIGCHLD, &sa, NULL) == -1)
							{
								perror("sigaction");
								exit(1);
							}

							printf("server: waiting for connections...\n");

							int no=0;
							int th=0,iret2;

							while(1) 
								{  // main accept() loop
														int t=0;
														sin_size = sizeof their_addr;
														new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
														int *pp=&new_fd;
														if (new_fd == -1) 
														{
																	perror("accept");
																	continue;
														}

														inet_ntop(their_addr.ss_family,
														get_in_addr((struct sockaddr *)&their_addr),s, sizeof s);
														printf("server: got connection from %s\n", s);

														//XXXXX---need to use realloc for struct list
														//list= (Client *)realloc((Client *)list,  sizeof(Client));
														//list=(Client *)malloc(5* sizeof(Client));
														numlist++;
														no=numlist-1;
														list[no].fdno=new_fd;
														curnum=no;
														
														

														//thread1= (pthread_t *)realloc((pthread_t *)thread1, 1 * sizeof(pthread_t));
														iret2 = pthread_create( &thread1[no], NULL, &threaded_server, (void *)new_fd);
														num=no;
														no++;
		
							}


								
								return 0;
		}





	void *threaded_server( void * ne)
	{
			int cur=curnum;
			int nefd= (int)ne;
			char buf[MAXDATASIZE];
			char bufsend[MAXDATASIZE];
				char bufhold[MAXDATASIZE];
			int t=0,numbytes;
			int no=0,th;
			list[cur].test=0;
			//head=append(&head, argu[2],z,x);
		
		while(1)
			{
									list[cur].test++;
									if ((numbytes = recv(nefd, buf, MAXDATASIZE-1, 0)) == -1)
									{
												perror("recv");
												exit(1);
									}

								buf[numbytes] = '\0';
										if(list[cur].test ==1)
										{
							strcpy(list[cur].name,buf);
										}
												if(list[cur].test ==2)
										{
						char *ch=		search(head,list[cur].name,buf);//get in your list[cur] passkey from DB
											//if(list[cur].passkey[0]!=' '){//check whether the stuff matched or not
						strcpy(list[cur].pass,buf);
						strcpy(list[cur].passkey,buf);//comment out this line
						list[cur].flag=1;
											//}
											//else{
												//close connection
											//add log
											//}
										}																

								

								int mm;
								if(list[cur].test >2)
								{
									strcpy(bufsend,list[cur].name);
								strcat(bufsend," : ");

								//decrypt the buf before concatenating using cur passkey
								strcat(bufsend,buf);
								strcpy(bufhold,bufsend);
								//char mes[100]="Server got it";
										for (mm=0;mm<=num ;mm++ )
										{
													strcpy(bufsend,bufhold);
													if(mm!=cur&&list[mm].flag==1) 
													{
													strcat(bufsend, " --passkey : ");//comment out this
	                                                   strcat(bufsend, list[mm].passkey);//encrypt bufsend with passkey using mm passkey
															if (send(list[mm].fdno, bufsend, strlen(bufsend), 0) == -1)
														   {
															//	printf("send in thread \n");
																perror("send prob ");
														   }



												  }
									  }

							   }
			//t++;
																															
		 }
																								
							close(nefd);  // parent doesn't need this
					
							
}
